using AdmissionQA.Application.Common;
using AdmissionQA.Application.Dtos.TuitionFee;
using AdmissionQA.Application.ServiceInterfaces;
using AdmissionQA.Domain.Entities;
using AdmissionQA.Domain.Repositorys;
using Microsoft.Extensions.Logging;

namespace AdmissionQA.Application.Services;

/// <summary>
/// 学费信息服务实现
/// </summary>
public class TuitionFeeServices(IRepository<TuitionFee> repository, ILogger<TuitionFeeServices> logger, ITextEmbeddingService embeddingService, IMajorInfoServices majorInfoServices)
    : ITuitionFeeServices
{
    private readonly IRepository<TuitionFee> _repository = repository;
    private readonly ILogger<TuitionFeeServices> _logger = logger;
    private readonly ITextEmbeddingService _embeddingService = embeddingService;
    private readonly IMajorInfoServices _majorInfoServices = majorInfoServices;

    /// <summary>
    /// 批量创建学费信息
    /// </summary>
    /// <param name="tuitionFees">学费信息列表</param>
    /// <returns>创建结果</returns>
    public async Task<Result<string>> CreateTuitionFeesAsync(TuitionFeesDto tuitionFees)
    {
        foreach (var item in tuitionFees.TuitionFees)
        {
            var res = await _majorInfoServices.GetMajorInfoByIdAsync(item.MajorId);
            if (res.Data == null)
            {
                _logger.LogWarning("批量创建学费信息失败：专业不存在，MajorId={MajorId}", item.MajorId);
                return Result<string>.Fail("专业不存在");
            }
        }

        var feesToCreate = tuitionFees
            .TuitionFees.Select(item =>
                TuitionFee.CreateTuitionFee(item.MajorId, item.TuitionAmount, item.AccommodationFee)
            )
            .Where(item => item != null)
            .Select(item => item!)
            .ToList();

        if (feesToCreate.Count == 0)
        {
            _logger.LogWarning("批量创建学费信息失败：没有有效的信息");
            return Result<string>.Fail("没有有效的学费信息可以创建");
        }

        await _repository.CreateRangeAsync(feesToCreate);
        _logger.LogInformation("批量创建学费信息成功，数量：{Count}", feesToCreate.Count);
        return Result<string>.Success("创建成功");
    }

    /// <summary>
    /// 创建学费信息
    /// </summary>
    /// <param name="tuitionFee">学费信息</param>
    /// <returns>创建结果</returns>
    public async Task<Result<string>> CreateTuitionFeeAsync(TuitionFeeDto tuitionFee)
    {
        var entity = TuitionFee.CreateTuitionFee(tuitionFee.MajorId, tuitionFee.TuitionAmount, tuitionFee.AccommodationFee);
        if (entity == null)
        {
            _logger.LogWarning("创建学费信息失败，参数：{@TuitionFee}", tuitionFee);
            return Result<string>.Fail("创建学费信息失败");
        }
        var content = tuitionFee.Description ?? "";
        entity.Embedding = _embeddingService.GetVector(content);
        await _repository.CreateAsync(entity);
        _logger.LogInformation("创建学费信息成功，专业ID：{MajorId}", tuitionFee.MajorId);
        return Result<string>.Success("创建成功");
    }

    /// <summary>
    /// 批量删除学费信息
    /// </summary>
    /// <param name="ids">学费信息ID列表</param>
    /// <returns>删除结果</returns>
    public async Task<Result<string>> DeleteTuitionFeesAsync(IEnumerable<Guid> ids)
    {
        // 并行获取所有学费信息
        var tasks = ids.Select(id => _repository.GetByIdAsync(id));
        var fees = await Task.WhenAll(tasks);

        // 过滤掉 null 值并转换为非空类型
        var validFees = fees.OfType<TuitionFee>().ToList();

        // 检查是否有有效的学费信息
        if (validFees.Count == 0)
        {
            _logger.LogWarning("批量删除学费信息失败：未找到任何信息，ids={@Ids}", ids);
            return Result<string>.Fail("没有找到学费信息");
        }

        // 调用 Delete 方法标记为删除
        foreach (var fee in validFees)
        {
            if (!fee.Delete())
            {
                _logger.LogWarning("批量删除学费信息时，信息已被删除，id={Id}", fee.Id);
                return Result<string>.Fail($"学费信息 {fee.Id} 已经被删除");
            }
        }

        // 更新所有有效的学费信息
        await _repository.UpdateRangeAsync(validFees);
        _logger.LogInformation("批量删除学费信息成功，数量：{Count}", validFees.Count);

        return Result<string>.Success("删除成功");
    }

    /// <summary>
    /// 删除学费信息
    /// </summary>
    /// <param name="id">学费信息ID</param>
    /// <returns>删除结果</returns>
    public async Task<Result<string>> DeleteTuitionFeeAsync(Guid id)
    {
        var fee = await _repository.GetByIdAsync(id);
        if (fee == null)
        {
            _logger.LogWarning("删除学费信息失败：未找到信息，id={Id}", id);
            return Result<string>.Fail("没有找到学费信息");
        }
        if (!fee.Delete())
        {
            _logger.LogWarning("删除学费信息失败：信息已被删除，id={Id}", id);
            return Result<string>.Fail("学费信息已经被删除");
        }
        await _repository.UpdateAsync(fee);
        _logger.LogInformation("删除学费信息成功，id={Id}", id);
        return Result<string>.Success("删除成功");
    }

    /// <summary>
    /// 根据ID获取学费信息
    /// </summary>
    /// <param name="id">学费信息ID</param>
    /// <returns>学费信息</returns>
    public async Task<Result<TuitionFeeWithMajorNameDto>> GetTuitionFeeByIdAsync(Guid id)
    {
        var fee = await _repository.GetByIdAsync(id);
        if (fee == null)
        {
            return Result<TuitionFeeWithMajorNameDto>.Fail("没有找到学费信息");
        }
        var res = await _majorInfoServices.GetMajorInfoByIdAsync(fee.MajorId);
        if (res.Data == null)
        {
            return Result<TuitionFeeWithMajorNameDto>.Fail("专业不存在");
        }
        var tuitionFee = new TuitionFeeWithMajorNameDto(
            id,
            res.Data.MajorName,
            fee.TuitionAmount,
            fee.AccommodationFee,
            fee.Description
        );
        return Result<TuitionFeeWithMajorNameDto>.Success(tuitionFee);
    }

    /// <summary>
    /// 获取学费信息数量
    /// </summary>
    /// <returns>学费信息数量</returns>
    public async Task<int> GetTuitionFeeCountAsync()
    {
        return await _repository.GetCountAsync();
    }

    /// <summary>
    /// 获取所有学费信息
    /// </summary>
    /// <returns>学费信息列表</returns>
    public async Task<Result<IEnumerable<TuitionFeeWithMajorNameDto>>> GetAllTuitionFeesAsync()
    {
        var fees = await _repository.GetAllAsync();
        var tuitionFees = new List<TuitionFeeWithMajorNameDto>();
        foreach (var fee in fees)
        {
            var res = await _majorInfoServices.GetMajorInfoByIdAsync(fee.MajorId);
            if (res.Data == null)
            {
                return Result<IEnumerable<TuitionFeeWithMajorNameDto>>.Fail("专业不存在");
            }
            tuitionFees.Add(
                new TuitionFeeWithMajorNameDto(
                    fee.Id,
                    res.Data.MajorName,
                    fee.TuitionAmount,
                    fee.AccommodationFee,
                    fee.Description
                )
            );
        }
        return Result<IEnumerable<TuitionFeeWithMajorNameDto>>.Success(tuitionFees);
    }

    /// <summary>
    /// 分页获取学费信息
    /// </summary>
    /// <param name="pageIndex">页码</param>
    /// <param name="pageSize">页大小</param>
    /// <returns>分页结果</returns>
    public async Task<Result<IEnumerable<TuitionFeeWithMajorNameDto>>> GetPagedTuitionFeesAsync(
        int pageIndex = 0,
        int pageSize = 10
    )
    {
        var fees = await _repository.GetPagedAsync(pageIndex, pageSize);
        var tuitionFees = new List<TuitionFeeWithMajorNameDto>();
        foreach (var fee in fees)
        {
            var res = await _majorInfoServices.GetMajorInfoByIdAsync(fee.MajorId);
            if (res.Data == null)
            {
                return Result<IEnumerable<TuitionFeeWithMajorNameDto>>.Fail("专业不存在");
            }
            tuitionFees.Add(
                new TuitionFeeWithMajorNameDto(
                    fee.Id,
                    res.Data.MajorName,
                    fee.TuitionAmount,
                    fee.AccommodationFee,
                    fee.Description
                )
            );
        }
        return Result<IEnumerable<TuitionFeeWithMajorNameDto>>.Success(tuitionFees);
    }

    /// <summary>
    /// 根据专业ID获取学费信息
    /// </summary>
    /// <param name="majorId">专业ID</param>
    /// <returns>匹配的学费信息列表</returns>
    public async Task<Result<IEnumerable<TuitionFeeWithMajorNameDto>>> GetTuitionFeesByMajorIdAsync(
        Guid majorId
    )
    {
        var fees = await _repository.GetListConditionAsync(item => item.MajorId == majorId);
        var tuitionFees = new List<TuitionFeeWithMajorNameDto>();
        foreach (var fee in fees)
        {
            var res = await _majorInfoServices.GetMajorInfoByIdAsync(fee.MajorId);
            if (res.Data == null)
            {
                return Result<IEnumerable<TuitionFeeWithMajorNameDto>>.Fail("专业不存在");
            }
            tuitionFees.Add(
                new TuitionFeeWithMajorNameDto(
                    fee.Id,
                    res.Data.MajorName,
                    fee.TuitionAmount,
                    fee.AccommodationFee,
                    fee.Description
                )
            );
        }
        return Result<IEnumerable<TuitionFeeWithMajorNameDto>>.Success(tuitionFees);
    }

    /// <summary>
    /// 更新学费信息
    /// </summary>
    /// <param name="id">学费信息ID</param>
    /// <param name="tuitionFee">学费信息</param>
    public async Task<Result<string>> UpdateTuitionFeeAsync(Guid id, TuitionFeeDto tuitionFee)
    {
        var entity = await _repository.GetByIdAsync(id);
        if (entity == null)
        {
            _logger.LogWarning("更新学费信息失败：未找到信息，id={Id}", id);
            return Result<string>.Fail("没有找到学费信息");
        }
        entity.UpdateTuitionFee(tuitionFee.MajorId, tuitionFee.TuitionAmount, tuitionFee.AccommodationFee, tuitionFee.Description);
        var content = tuitionFee.Description ?? "";
        entity.Embedding = _embeddingService.GetVector(content);
        await _repository.UpdateAsync(entity);
        _logger.LogInformation("更新学费信息成功，id={Id}", id);
        return Result<string>.Success("更新成功");
    }

    public async Task<Result<IEnumerable<TuitionFee>>> SearchTuitionFeesByEmbeddingAsync(string text, int topK = 5)
    {
        var queryEmbedding = _embeddingService.GetVector(text);
        var all = await _repository.GetAllAsync();
        var withScore = all.Where(x => x.Embedding != null)
            .Select(x => new { Entity = x, Score = CosineSimilarity(queryEmbedding, x.Embedding!) })
            .OrderByDescending(x => x.Score)
            .Take(topK)
            .Select(x => x.Entity)
            .ToList();
        return Result<IEnumerable<TuitionFee>>.Success(withScore);
    }
    private static float CosineSimilarity(float[] v1, float[] v2)
    {
        if (v1 == null || v2 == null || v1.Length != v2.Length) return 0f;
        float dot = 0, norm1 = 0, norm2 = 0;
        for (int i = 0; i < v1.Length; i++)
        {
            dot += v1[i] * v2[i];
            norm1 += v1[i] * v1[i];
            norm2 += v2[i] * v2[i];
        }
        if (norm1 == 0 || norm2 == 0) return 0f;
        return dot / (float)(Math.Sqrt(norm1) * Math.Sqrt(norm2));
    }
}
